﻿namespace LogManager.Core.Models
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Xml.Linq;
    using LogManager.Core.Factories;
    using Moq;
    using NSubstitute;
    using NUnit.Framework;

    public class TestServer
    {
        [Test]
        public void Server_Ctor_CheckProperties_Ok()
        {
            var plateform = Substitute.For<IPlateform>();
            var modelsFactory = Substitute.For<IXmlElementFactory>();

            var template = @"<Server Name=""testName"" Ip=""testIp"" RetentionHours=""40""></Server>";
            var xml = XElement.Parse(template);
            var server = new Server(xml, plateform, modelsFactory);

            Assert.AreEqual(server.ParentPlateform, plateform);
            Assert.AreEqual(server.BaseNode, xml);
            Assert.AreEqual(server.Ip, "testIp");
            Assert.AreEqual(server.Name, "testName");
            Assert.AreEqual(server.RetentionHours, 40);
            Assert.AreEqual(server.RetentionDuration, TimeSpan.FromHours(40));
        }

        [Test]
        public void Server_Ctor_CheckSubLocationCreation_Ok()
        {
            var plateform = Substitute.For<IPlateform>();
            var modelsFactory = Substitute.For<IXmlElementFactory>();
            var fakeServer = Substitute.For<IServer>();

            var template = @"<Server Name=""testName"" Ip=""testIp"" RetentionHours=""40"">
            <Location>test1</Location>
            <Location>test2</Location>
            </Server>";

            var location1 = new Location(XElement.Parse(Location.DEFAULT_TEMPLATE), fakeServer);
            var location2 = new Location(XElement.Parse(Location.DEFAULT_TEMPLATE), fakeServer);
            modelsFactory.CreateLocation(Arg.Any<XElement>(), Arg.Any<IServer>()).Returns(location1, location2);

            var xml = XElement.Parse(template);
            var server = new Server(xml, plateform, modelsFactory);

            Assert.AreEqual(server.Locations.Count, 2);
            modelsFactory.Received(2).CreateLocation(Arg.Any<XElement>(), server);

            Assert.AreEqual(server.Locations.First(), location1);
            Assert.AreEqual(server.Locations.Skip(1).First(), location2);
        }

        [Test]
        public void Server_AddNewLocation_CallMethod_CheckLocationAdded()
        {
            var plateform = Substitute.For<IPlateform>();
            var modelsFactory = Substitute.For<IXmlElementFactory>();

            var template = @"<Server Name=""testName"" Ip=""testIp"" RetentionHours=""40""></Server>";

            var xml = XElement.Parse(template);
            var server = new Server(xml, plateform, modelsFactory);

            var locationToAdd = new Location(XElement.Parse(Location.DEFAULT_TEMPLATE), Substitute.For<IServer>());
            modelsFactory.CreateNewLocation(server).Returns(locationToAdd);

            // when
            var addedLocation = server.AddNewLocation();

            // assert
            Assert.AreEqual(server.Locations.Count, 1);
            Assert.AreEqual(server.Locations.Single(), addedLocation);
            Assert.AreEqual(locationToAdd, addedLocation);
            modelsFactory.Received(1).CreateNewLocation(server);
        }

        [Test]
        public void Server_DeleteServer_CallMethod_ServerDeletedFromParentPlateform()
        {
            var plateform = Substitute.For<IPlateform>();
            var modelsFactory = Substitute.For<IXmlElementFactory>();

            var template = @"<Server Name=""testName"" Ip=""testIp"" RetentionHours=""40""></Server>";

            var xml = XElement.Parse(template);
            var server = new Server(xml, plateform, modelsFactory);

            plateform.Servers.Returns(new ObservableCollection<IServer>());
            plateform.Servers.Add(server);

            // when
            server.DeleteServer();

            // assert
            Assert.AreEqual(plateform.Servers.Count, 0);
        }

        [Test]
        public void Server_SaveChanges_ModifyProperties_ChangesPersistedToBaseNode()
        {
            var plateform = Substitute.For<IPlateform>();
            var modelsFactory = Substitute.For<IXmlElementFactory>();
            var template = @"<Server Name=""testName"" Ip=""testIp"" RetentionHours=""40""></Server>";

            var xml = XElement.Parse(template);
            var server = new Server(xml, plateform, modelsFactory);

            server.Name = "testName1";
            server.Ip = "testIp1";
            server.RetentionHours = 41;

            // when
            server.SaveChanges();

            // assert
            Assert.IsTrue(XNode.DeepEquals(server.BaseNode, XElement.Parse(@"<Server Name=""testName1"" Ip=""testIp1"" RetentionHours=""41""></Server>")));
        }


        [Test]
        public void Server_SaveChanges_UpdateLocationList_ChangesPersistedToBaseNode()
        {
            var plateform = Substitute.For<IPlateform>();
            var modelsFactory = Substitute.For<IXmlElementFactory>();
            var template = @"<Server Name=""testName"" Ip=""testIp"" RetentionHours=""40""></Server>";

            var xml = XElement.Parse(template);
            var server = new Server(xml, plateform, modelsFactory);

            var location = Substitute.For<ILocation, IXmlElement>();
            ((IXmlElement)location).BaseNode.Returns(XElement.Parse("<Location>test1</Location>"));

            server.Locations.Add(location);

            // when
            server.SaveChanges();

            // assert
            Assert.IsTrue(XNode.DeepEquals(server.BaseNode, XElement.Parse(@"<Server Name=""testName"" Ip=""testIp"" RetentionHours=""40""><Location>test1</Location></Server>")));
        }


        [Test]
        public void Server_SaveChanges_IsCalledWhenPropertyChanges_Called()
        {
            var plateform = Substitute.For<IPlateform>();
            var modelsFactory = Substitute.For<IXmlElementFactory>();
            var template = @"<Server Name=""testName"" Ip=""testIp"" RetentionHours=""40""></Server>";

            var xml = XElement.Parse(template);
            var server = new Mock<Server>(xml, plateform, modelsFactory) { CallBase = true };
            var loca = Substitute.ForPartsOf<Location>(XElement.Parse(Location.DEFAULT_TEMPLATE), Substitute.For<IServer>());

            // when
            server.Object.RaisePropertyChanged("propName");
        
            // assert
            server.Verify( p =>  p.SaveChanges());
        }
    }
}
